﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace RC4
{
    public interface ICoder
    {
        void Encrypt(string password, string file, string targetFile);
        void Decrypt(string password, string file, string targetFile);
    }
    class RC4 : ICoder
    {
        //private const int EncodingCode = 1251;

        public void Encrypt(string password, string file, string targetFile)
        {
            byte[] passwordToPass = System.Text.Encoding.Default.GetBytes(password);
            byte[] content = encrypt(passwordToPass, File.ReadAllBytes(file));
            File.WriteAllBytes(targetFile, content);
        }

        public void Decrypt(string password, string file, string targetFile)
        {
            Encrypt(password, file, targetFile);
        }

        private byte[] encrypt(byte[] password, byte[] data)
        {
            int a, i, j, k, tmp, pwd_length, data_length;
            int[] key, sbox;
            byte[] cipheredData;

            pwd_length = password.Length;
            data_length = data.Length;
            key = new int[256];
            sbox = new int[256];
            cipheredData = new byte[data.Length];

            for (i = 0; i < 256; i++)
            {
                key[i] = password[i % pwd_length];
                sbox[i] = i;
            }
            for (j = i = 0; i < 256; i++)
            {
                j = (j + sbox[i] + key[i]) % 256;
                tmp = sbox[i];
                sbox[i] = sbox[j];
                sbox[j] = tmp;
            }
            for (a = j = i = 0; i < data_length; i++)
            {
                a = (a + 1) % 256;
                j = (j + sbox[a]) % 256;

                //swap
                tmp = sbox[a];
                sbox[a] = sbox[j];
                sbox[j] = tmp;

                k = sbox[((sbox[a] + sbox[j]) % 256)];
                cipheredData[i] = (byte)(data[i] ^ k);
            }
            return cipheredData;
        }
    }
}
